using System;
using System.ComponentModel;
using System.IO;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content.Pipeline;
using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
using Microsoft.Xna.Framework.Content.Pipeline.Processors;

namespace Phoenix.Xna.Framework.ContentPipeline.Models
{
    [ContentProcessor(DisplayName = "Skinned Model Material - Phoenix XNA Engine"), DesignTimeVisible(false)]
    internal class SkinnedModelMaterialProcessor : MaterialProcessor
    {
        public static readonly string DiffuseMapKey = "Texture";
        public static readonly string NormalMapKey = "Bump0";
        public static readonly string SpecularMapKey = "Specular0";
        private static readonly char[] DirectorySeparatorChars = new char[] { '/', '\\' };

        [DisplayName("Texture Path"),
            Description("If set, changes the path of all texture resources.  The new path can be an absolute or relative path."),
            DefaultValue(typeof(string), "")]
        public virtual string TexturePath { get; set; }
        [DisplayName("Texture Path Type"),
            Description("Indicates whether the \"Texture Path\" is an absolute or relative path.  If the path is relative, it is relative to the source asset path."),
            DefaultValue(typeof(PathType), "Relative")]
        public virtual PathType TexturePathType { get; set; }

        private void ProcessTextures(MaterialContent input, SkinnedModelMaterialContent skinnedModelMaterial,
            ContentProcessorContext context)
        {
            foreach (string key in input.Textures.Keys)
            {
                ExternalReference<TextureContent> texture = input.Textures[key];

                if (!String.IsNullOrEmpty(TexturePath))
                {
                    string fullFilePath;

                    if (TexturePathType == PathType.Relative)
                    {
                        string sourceAssetPath = Path.GetDirectoryName(input.Identity.SourceFilename);
                        fullFilePath = Path.GetFullPath(Path.Combine(sourceAssetPath, TexturePath));
                    }
                    else
                    {
                        fullFilePath = TexturePath;
                    }

                    texture.Filename = Path.Combine(fullFilePath, Path.GetFileName(texture.Filename));
                }

                ProcessTexture(key, texture, skinnedModelMaterial, context);
            }
        }

        protected virtual void ProcessTexture(string key, ExternalReference<TextureContent> texture,
            SkinnedModelMaterialContent skinnedModelMaterial, ContentProcessorContext context)
        {
            if (key.Equals(DiffuseMapKey))
            {
                skinnedModelMaterial.IsDiffusedMapped = true;
                skinnedModelMaterial.DiffuseMapContent = base.BuildTexture(key, texture, context);
            }
            else if (key.Equals(NormalMapKey))
            {
                skinnedModelMaterial.IsNormalMapped = true;
                skinnedModelMaterial.NormalMapContent = base.BuildTexture(key, texture, context);
            }
            else if (key.Equals(SpecularMapKey))
            {
                skinnedModelMaterial.IsSpecularMappped = true;
                skinnedModelMaterial.SpecularMapContent = base.BuildTexture(key, texture, context);
            }
        }

        protected virtual void ProcessMaterial(MaterialContent input,
            SkinnedModelMaterialContent skinnedModelMaterial, ContentProcessorContext context)
        {
            BasicMaterialContent basicMaterial = input as BasicMaterialContent;

            if (basicMaterial != null)
            {
                skinnedModelMaterial.EmissiveColor = basicMaterial.EmissiveColor.GetValueOrDefault(Vector3.Zero);
                skinnedModelMaterial.DiffuseColor = basicMaterial.DiffuseColor.GetValueOrDefault(Vector3.One);
                skinnedModelMaterial.SpecularColor = basicMaterial.SpecularColor.GetValueOrDefault(Vector3.One);
                skinnedModelMaterial.SpecularPower = basicMaterial.SpecularPower.GetValueOrDefault(16);
            }

        }

        #region MaterialProcessor Members

        public override MaterialContent Process(MaterialContent input, ContentProcessorContext context)
        {
            SkinnedModelMaterialContent skinnedModelMaterialContent = new SkinnedModelMaterialContent();
            ProcessTextures(input, skinnedModelMaterialContent, context);
            ProcessMaterial(input, skinnedModelMaterialContent, context);
            return skinnedModelMaterialContent;
        }

        #endregion
    }
}